/**
 * 
 */
package qy.jalgotrade.event;

import java.time.ZonedDateTime;

/**
 * 主题 (事件源)
 * 
 * @author c-geo
 *
 */
public abstract class Subject {

	private Dispatcher.DispatcherPrio __dispatchPrio;

	/**
	 * 在 {@link #preDispatch()} 和 {@link #dispatch()} 之间为 true, 其余状态均为 false:
	 */
	private boolean __isDispatching;

	public Subject() {

		__dispatchPrio = Dispatcher.DispatcherPrio.LAST;
		__isDispatching = false;
	}

	/**
	 * This may raise.
	 */
	public abstract void start();

	/**
	 * This should not raise.
	 */
	public abstract void stop();

	/**
	 * This should not raise.
	 */
	public abstract void join();

	/**
	 * Return True if there are not more events to dispatch.
	 */
	public abstract boolean eof();

	/**
	 * 是否处于 {@link #preDispatch() 和 {@link #dispatch()} 之间的 中间状态. (在 {@link #preDispatch()} 和
	 * {@link #dispatch()} 之间为 true, 其余状态均为 false)
	 * 
	 * @return
	 */
	public boolean isDispatching() {

		return __isDispatching;
	}

	/**
	 * Called by {@link Dispatcher Dispatcher}.
	 * 
	 * @throws Exception
	 */
	public final void __doPreDispatch() throws Exception {

//		__isDispatching = true;
		preDispatch();
		__isDispatching = true;
	}

	/**
	 * Called by {@link Dispatcher Dispatcher}.
	 * 
	 * @throws Exception
	 */
	public final boolean __doDispatch() throws Exception {

		assert isDispatching() : "Must after preDispatch() !";

		__isDispatching = false;
		return dispatch();
	}

	/**
	 * TODO: Pre-Dispatch events (update resampled BarFeed, etc.). If True is returned, it means that at
	 * least one event was dispatched. <br />
	 * 进行 resampled BarFeed 更新等预处理操作:
	 * 
	 * @return
	 * @throws Exception
	 */
	public abstract void preDispatch() throws Exception;

	/**
	 * Dispatch events. If True is returned, it means that at least one event was dispatched. <br />
	 * 分发 事件, 委派 事件处理器 进行 事件处理 的实现:
	 * 
	 * @return
	 * @throws Exception
	 */
	public abstract boolean dispatch() throws Exception;

	/**
	 * Return the datetime for the next event.<br />
	 * This is needed to properly synchronize non-realtime subjects.<br />
	 * Return None since this is a realtime subject.
	 */
	public abstract ZonedDateTime peekDateTime();

	/**
	 * Returns a priority used to sort subjects within the dispatch queue.<br />
	 * The return value should never change once this subject is added to the dispatcher.
	 * 
	 * @return
	 */
	public Dispatcher.DispatcherPrio getDispatchPriority() {

		return __dispatchPrio;
	}

	public void setDispatchPriority(Dispatcher.DispatcherPrio dispatchPrio) {

		__dispatchPrio = dispatchPrio;
	}

	/**
	 * Called when the subject is registered with a dispatcher.
	 * 
	 * @param dispatcher
	 */
	public void onDispatcherRegistered(Dispatcher dispatcher) {

	}
}
